{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# API 키를 환경변수로 관리하기 위한 설정 파일\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "# API 키 정보 로드\n",
    "load_dotenv()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Chain of Density: https://arxiv.org/pdf/2309.04269.pdf\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "import textwrap\n",
    "\n",
    "from langchain import hub\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain.output_parsers.json import SimpleJsonOutputParser\n",
    "from langchain.document_loaders import WebBaseLoader\n",
    "from langchain.schema.runnable import RunnablePassthrough\n",
    "\n",
    "# Load some data to summarize\n",
    "loader = WebBaseLoader(\"https://teddylee777.github.io/data-science/optuna/\")\n",
    "docs = loader.load()\n",
    "content = docs[0].page_content\n",
    "\n",
    "# Get this prompt template\n",
    "prompt = hub.pull(\"lawwu/chain_of_density\")\n",
    "\n",
    "# The chat model output is a JSON list of dicts, with SimpleJsonOutputParser\n",
    "# we can convert it o a dict, and it suppors streaming.\n",
    "json_parser = SimpleJsonOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = (\n",
    "    {\"ARTICLE\": RunnablePassthrough()}\n",
    "    | prompt\n",
    "    | ChatOpenAI(model=\"gpt-3.5-turbo-16k\", temperature=0.1)\n",
    "    | json_parser\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'Missing_Entities': 'Optuna; data science',\n",
       "  'Denser_Summary': 'This article discusses Optuna, a data science tool. Optuna is a library for hyperparameter optimization. It provides a simple and efficient way to search for the best hyperparameters for machine learning models. With Optuna, you can easily tune the parameters of your models and improve their performance. It is a powerful tool for data scientists and machine learning practitioners.'},\n",
       " {'Missing_Entities': 'trial.suggest_categorical(); trial.suggest_int(); trial.suggest_float()',\n",
       "  'Denser_Summary': 'Optuna provides several methods for suggesting hyperparameters. One of them is trial.suggest_categorical(), which allows you to choose from a set of predefined values. Another method is trial.suggest_int(), which suggests integer values within a specified range. Lastly, trial.suggest_float() suggests floating-point values within a given range. These methods are useful for exploring different hyperparameter values and finding the best combination for your model.'},\n",
       " {'Missing_Entities': 'objective function; KFold; mean_squared_error',\n",
       "  'Denser_Summary': \"The objective function is a crucial part of using Optuna. It is the function that you want to optimize, such as minimizing the mean squared error. Optuna supports various evaluation metrics, including mean squared error. To evaluate the performance of your model, you can use KFold cross-validation, which splits the data into multiple folds for training and testing. This helps to ensure a more robust evaluation of your model's performance.\"},\n",
       " {'Missing_Entities': 'study.best_params; RandomForestRegressor',\n",
       "  'Denser_Summary': 'After optimizing with Optuna, you can access the best parameters found using study.best_params. These parameters can then be used to create a RandomForestRegressor model, which is a powerful algorithm for regression tasks. By using the best parameters, you can improve the performance of your model and make more accurate predictions.'},\n",
       " {'Missing_Entities': 'LangChain; LCEL; OpenAI API',\n",
       "  'Denser_Summary': 'LangChain is a platform that utilizes the LangChain Expression Language (LCEL) to process and analyze data. LCEL is a powerful language that allows for complex data transformations and analysis. Additionally, LangChain integrates with the OpenAI API, providing access to advanced natural language processing capabilities. With LangChain and the OpenAI API, you can perform sophisticated data analysis and gain valuable insights from your data.'}]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke(content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "```json\n",
      "[\n",
      "    {\n",
      "        \"Missing_Entities\": \"\",\n",
      "        \"Denser_Summary\": \"이 기사는 데이터사이언스, 머신러닝, 인공지능에 대한 개념을 설명하고 있습니다. 이 분야들이 우리 생활에 어떻게 적용되고 있는지, 그리고 이 분야를 공부하고자 하는 사람들이 어떻게 시작해야 할지에 대한 정보를 제공합니다. 또한, 이 기술들이 어떻게 빠르게 발전하고 있는지에 대한 설명도 포함하고 있습니다. 이러한 기술들의 정의와 차이점, 그리고 이 분야에서 일하려면 어떤 준비가 필요한지에 대한 내용도 다루고 있습니다.\"\n",
      "    },\n",
      "    {\n",
      "        \"Missing_Entities\": \"박정현 서울대 EPM 연구원; '인공지능 국가전략' 발표; 퍼듀 대학의 윌리엄 클리블랜드 교수\",\n",
      "        \"Denser_Summary\": \"박정현 서울대 EPM 연구원이 작성한 이 기사는 데이터사이언스, 머신러닝, 인공지능의 개념과 실생활 적용 예를 설명합니다. '인공지능 국가전략' 발표와 같은 국가적 노력과 퍼듀 대학의 윌리엄 클리블랜드 교수의 이론을 포함해, 이 분야의 학문적, 실용적 측면을 다룹니다. 또한, 이 기술들의 발전 속도와 이 분야에 대한 관심이 증가하는 이유를 설명하며, 이 분야를 공부하려는 이들에게 시작점을 제시합니다.\"\n",
      "    },\n",
      "    {\n",
      "        \"Missing_Entities\": \"튜링테스트; 지도학습(supervised learning)과 비지도 학습(unsupervised learning)\",\n",
      "        \"Denser_Summary\": \"박정현 서울대 EPM 연구원이 작성한 이 기사는 데이터사이언스, 머신러닝, 인공지능의 정의와 '인공지능 국가전략', 퍼듀 대학의 윌리엄 클리블랜드 교수의 이론을 포함해 설명합니다. 튜링테스트와 지도학습, 비지도 학습의 개념을 통해 인공지능의 실용적 적용을 다루며, 이 분야의 발전과 공부 방향에 대한 조언을 제공합니다.\"\n",
      "    },\n",
      "    {\n",
      "        \"Missing_Entities\": \"알파고; GPT-3; 데이터 피처 엔지니어링\",\n",
      "        \"Denser_Summary\": \"박정현 서울대 EPM 연구원이 작성한 이 기사는 데이터사이언스, 머신러닝, 인공지능의 정의와 '인공지능 국가전략', 퍼듀 대학의 윌리엄 클리블랜드 교수의 이론을 포함해 설명합니다. 알파고, GPT-3 예시와 튜링테스트, 지도학습, 비지도 학습을 통해 인공지능의 실용적 적용을 다루며, 데이터 피처 엔지니어링의 중요성과 이 분야의 발전 방향을 제시합니다.\"\n",
      "    },\n",
      "    {\n",
      "        \"Missing_Entities\": \"k-means; 이상값 검출(anomaly detection); 강화학습(reinforce learning)\",\n",
      "        \"Denser_Summary\": \"박정현 서울대 EPM 연구원이 작성한 이 기사는 데이터사이언스, 머신러닝, 인공지능의 정의와 '인공지능 국가전략', 퍼듀 대학의 윌리엄 클리블랜드 교수의 이론을 포함해 설명합니다. 알파고, GPT-3 예시와 튜링테스트, 지도학습, 비지도 학습을 통해 인공지능의 실용적 적용을 다루며, k-means, 이상값 검출, 강화학습의 알고리즘과 데이터 피처 엔지니어링의 중요성을 강조합니다.\"\n",
      "    }\n",
      "]\n",
      "```박정현 서울대 EPM 연구원이 작성한 이 기사는 데이터사이언스, 머신러닝, 인공지능의 정의와 '인공지능 국가전략', 퍼듀 대학의 윌리엄 클리블랜드 교수의 이론을 포함해 설명합니다. 알파고, GPT-3 예시와 튜링테스트, 지도학습, 비지도 학습을 통해 인공지능의 실용적 적용을 다루며, k-means, 이상값 검출, 강화학습의 알고리즘과 데이터 피처 엔지니어링의 중요성을 강조합니다.\n"
     ]
    }
   ],
   "source": [
    "from langchain import hub\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.output_parsers import StrOutputParser, JsonOutputParser\n",
    "from langchain.document_loaders import WebBaseLoader\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from langchain.callbacks.base import BaseCallbackHandler\n",
    "import json\n",
    "\n",
    "\n",
    "# Load some data to summarize\n",
    "loader = WebBaseLoader(\n",
    "    \"https://www.aitimes.com/news/articleView.html?idxno=131777\")\n",
    "docs = loader.load()\n",
    "content = docs[0].page_content\n",
    "# Load the prompt\n",
    "# prompt = hub.pull(\"langchain-ai/chain-of-density:4f55305e\")\n",
    "\n",
    "\n",
    "class StreamCallback(BaseCallbackHandler):\n",
    "    def on_llm_new_token(self, token, **kwargs):\n",
    "        print(token, end=\"\", flush=True)\n",
    "\n",
    "\n",
    "prompt = ChatPromptTemplate.from_template(\n",
    "    \"\"\"Article: {ARTICLE}\n",
    "You will generate increasingly concise, entity-dense summaries of the above article. \n",
    "\n",
    "Repeat the following 2 steps 5 times. \n",
    "\n",
    "Step 1. Identify 1-3 informative entities (\";\" delimited) from the article which are missing from the previously generated summary. \n",
    "Step 2. Write a new, denser summary of identical length which covers every entity and detail from the previous summary plus the missing entities. \n",
    "\n",
    "A missing entity is:\n",
    "- relevant to the main story, \n",
    "- specific yet concise (50 words or fewer), \n",
    "- novel (not in the previous summary), \n",
    "- faithful (present in the article), \n",
    "- anywhere (can be located anywhere in the article).\n",
    "\n",
    "Guidelines:\n",
    "\n",
    "- The first summary should be long (8-10 sentences, ~200 words) yet highly non-specific, containing little information beyond the entities marked as missing. Use overly verbose language and fillers (e.g., \"this article discusses\") to reach ~200 words.\n",
    "- Make every word count: rewrite the previous summary to improve flow and make space for additional entities.\n",
    "- Make space with fusion, compression, and removal of uninformative phrases like \"the article discusses\".\n",
    "- The summaries should become highly dense and concise yet self-contained, i.e., easily understood without the article. \n",
    "- Missing entities can appear anywhere in the new summary.\n",
    "- Never drop entities from the previous summary. If space cannot be made, add fewer new entities. \n",
    "\n",
    "Remember, use the exact same number of words for each summary.\n",
    "Answer in JSON. The JSON should be a list (length 5) of dictionaries whose keys are \"Missing_Entities\" and \"Denser_Summary\".\n",
    "Use only KOREAN language to reply.\"\"\"\n",
    ")\n",
    "\n",
    "\n",
    "# Create the chain, including\n",
    "chain = (\n",
    "    prompt\n",
    "    | ChatOpenAI(\n",
    "        temperature=0,\n",
    "        model=\"gpt-4-turbo-preview\",\n",
    "        streaming=True,\n",
    "        callbacks=[StreamCallback()],\n",
    "    )\n",
    "    | JsonOutputParser()\n",
    "    | (lambda x: x[-1][\"Denser_Summary\"])\n",
    ")\n",
    "\n",
    "# Invoke the chain\n",
    "result = chain.invoke({\"ARTICLE\": content})\n",
    "print(result)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py-test",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
